package org.study.mybatisplus.dynamic.boot.service.impl;

import cn.hutool.core.date.*;
import cn.hutool.core.lang.tree.*;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.osgi.framework.ServiceException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.study.mybatisplus.dynamic.boot.config.SystemConstant;
import org.study.mybatisplus.dynamic.boot.config.TypeEnum.*;
import org.study.mybatisplus.dynamic.boot.mapper.DeviceRelationMapper;
import org.study.mybatisplus.dynamic.boot.mapper.IotDatasourceMapper;
import org.study.mybatisplus.dynamic.boot.model.DeviceRelation;
import org.study.mybatisplus.dynamic.boot.service.StatisticalService;
import org.study.mybatisplus.dynamic.boot.vo.*;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 作用描述
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2024年10月21日
 */
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Service
public class StatisticalServiceImpl implements StatisticalService {
    private final DeviceRelationMapper deviceRelationMapper;
    private final IotDatasourceMapper iotDatasourceMapper;

    @Override
    public List<Map<String, String>> electricityStatistics(Long projectId) {
        List<DeviceRelation> deviceList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getParentId, 0)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.SHU_CAI.getType())
        );
        if (CollectionUtils.isEmpty(deviceList)) {
            return Collections.emptyList();
        }
        List<DeviceRelation> devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                .isNotNull(DeviceRelation::getPropertyNo)
                .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_LJ.getType())
        );
        if (CollectionUtils.isEmpty(devicePropertyList)) {
            return Collections.emptyList();
        }
        List<Map<String, String>> resultList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        for (int i = 1; i <= 20; i++) {// 模拟20个电站
            List<String> sqlList = Lists.newArrayList();
            devicePropertyList.forEach(deviceProperty -> {
                String tableName = "property_" + projectId + "_" + deviceProperty.getDeviceId() + "_0";
                String sql = " SELECT " + deviceProperty.getDeviceId() + " AS deviceId, _wstart AS `time`, last_row(`" + deviceProperty.getPropertyNo() + "`) AS dataValue "
                        + " FROM " + tableName;
                sqlList.add(sql);
            });
            List<DataValueVO> dataValueList = Lists.newArrayList();
            try {
                DynamicDataSourceContextHolder.push(dsTdengine);
                String currentDs = DynamicDataSourceContextHolder.peek();
                // List<LinkedHashMap<String, Object>> mapList = iotDatasourceMapper.parseListMap4Tdengine(StrUtil.join(" UNION ALL ", sqlList));
                // log.info(JSON.toJSONString(mapList));
                dataValueList = iotDatasourceMapper.parseBean4TDengine(StrUtil.join(" UNION ALL ", sqlList));
                log.info(JSON.toJSONString(dataValueList));
            } catch (Exception ex) {
                log.error("子站总发电量统计，异常", ex);
                throw new ServiceException("子站总发电量统计，操作数据源【" + dsTdengine + "】失败");
            } finally {
                DynamicDataSourceContextHolder.clear();
            }
            BigDecimal totalSum = BigDecimal.ZERO;
            for (DataValueVO dataValueVO : dataValueList) {
                totalSum = totalSum.add(new BigDecimal(dataValueVO.getDataValue().toString()));
            }
            /*BigDecimal totalSum = dataValueList.stream().map(dataValueVO -> {
                BigDecimal bigDecimal = BigDecimal.ZERO;
                if (dataValueVO.getDataValue() != null) {
                    bigDecimal = new BigDecimal(dataValueVO.getDataValue().toString());
                }
                return bigDecimal;
            }).reduce(BigDecimal.ZERO, BigDecimal::add);*/
            Map<String, String> tempMap = Maps.newTreeMap();
            tempMap.put("name", "电站-" + i);
            tempMap.put("value", totalSum.toPlainString());
            resultList.add(tempMap);
        }
        return resultList;
    }

    @Override
    public List<Map<String, String>> electricityStatistics(Long projectId, String groupType, String datetime) {
        List<Map<String, String>> resultList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        for (int i = 0; i < 20; i++) {// 模拟20个电站
            List<DeviceRelation> devicePropertyList = Lists.newArrayList();
            String startTime, endTime;
            if (StatisticsType.STATISTICS_TYPE_YEAR.equals(groupType)) {
                DateTime startOfMonth = DateTime.of(datetime + "-01-01", "yyyy-MM-dd");
                DateTime endOfMonth = DateTime.of(datetime + "-12-31", "yyyy-MM-dd");
                startTime = DateUtil.format(DateUtil.beginOfDay(startOfMonth), "yyyy-MM-dd HH:mm:ss");
                endTime = DateUtil.format(DateUtil.endOfDay(endOfMonth), "yyyy-MM-dd HH:mm:ss");
                devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                        .eq(DeviceRelation::getProjectId, projectId)
                        .eq(DeviceRelation::getIsRealDevice, 1)
                        .isNotNull(DeviceRelation::getPropertyNo)
                        .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_DN.getType())
                );
            } else if (StatisticsType.STATISTICS_TYPE_MONTH.equals(groupType)) {
                DateTime dayDateTime = DateTime.of(datetime + "-01", "yyyy-MM-dd");
                DateTime startOfMonth = DateUtil.beginOfMonth(dayDateTime);
                DateTime endOfMonth = DateUtil.endOfMonth(dayDateTime);
                startTime = DateUtil.format(startOfMonth, "yyyy-MM-dd HH:mm:ss");
                endTime = DateUtil.format(endOfMonth, "yyyy-MM-dd HH:mm:ss");
                devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                        .eq(DeviceRelation::getProjectId, projectId)
                        .eq(DeviceRelation::getIsRealDevice, 1)
                        .isNotNull(DeviceRelation::getPropertyNo)
                        .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_DY.getType())
                );
            } else {
                throw new ServiceException("暂不支持当前维度");
            }
            if (CollectionUtils.isEmpty(devicePropertyList)) {
                return Collections.emptyList();
            }
            List<String> sqlList = Lists.newArrayList();
            devicePropertyList.forEach(deviceProperty -> {
                String tableName = "property_" + projectId + "_" + deviceProperty.getDeviceId() + "_0";
                String sql = "("
                        + " SELECT " + deviceProperty.getDeviceId() + " AS deviceId, _wstart AS `time`, last_row(`" + deviceProperty.getPropertyNo() + "`) AS dataValue "
                        + " FROM " + tableName + " "
                        + " WHERE `time` >= '" + startTime + "' and `time` <= '" + endTime + "' "
                        + ")";
                sqlList.add(sql);
            });
            List<DataValueVO> dataValueList = Lists.newArrayList();
            try {
                DynamicDataSourceContextHolder.push(dsTdengine);
                String currentDs = DynamicDataSourceContextHolder.peek();
                dataValueList = iotDatasourceMapper.parseBean4TDengine(StrUtil.join(" UNION ALL ", sqlList));
                log.info(JSON.toJSONString(dataValueList));
            } catch (Exception ex) {
                log.error("全站总发电量统计，异常", ex);
                throw new ServiceException("全站总发电量统计，操作数据源【" + dsTdengine + "】失败");
            } finally {
                DynamicDataSourceContextHolder.clear();
            }
            BigDecimal totalSum = BigDecimal.ZERO;
            for (DataValueVO dataValueVO : dataValueList) {
                totalSum = totalSum.add(new BigDecimal(dataValueVO.getDataValue().toString()));
            }
            /*BigDecimal totalSum = dataValueList.stream().map(dataValueVO -> {
                BigDecimal bigDecimal = BigDecimal.ZERO;
                if (dataValueVO.getDataValue() != null) {
                    bigDecimal = new BigDecimal(dataValueVO.getDataValue().toString());
                }
                return bigDecimal;
            }).reduce(BigDecimal.ZERO, BigDecimal::add);*/
            Map<String, String> tempMap = Maps.newTreeMap();
            tempMap.put("name", "电站-" + i);
            tempMap.put("value", totalSum.toPlainString());
            resultList.add(tempMap);
        }
        return resultList;
    }

    @Override
    public List<Map<String, String>> electricityStatistics(Long projectId, Long powerStationId, String groupType, String datetime) {
        List<DeviceRelation> deviceList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getParentId, 0)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.SHU_CAI.getType())
        );
        if (CollectionUtils.isEmpty(deviceList)) {
            return Collections.emptyList();
        }
        List<DeviceRelation> devicePropertyList = Lists.newArrayList();
        List<Map<String, String>> resultList = Lists.newArrayList();
        List<String> dateList = Lists.newArrayList();
        String intervals, startTime, endTime;
        if (StatisticsType.STATISTICS_TYPE_YEAR.equals(groupType)) {
            intervals = "1n";
            DateTime startOfMonth = DateTime.of(datetime + "-01-01", "yyyy-MM-dd");
            DateTime endOfMonth = DateTime.of(datetime + "-12-31", "yyyy-MM-dd");
            startTime = DateUtil.format(DateUtil.beginOfDay(startOfMonth), "yyyy-MM-dd HH:mm:ss");
            endTime = DateUtil.format(DateUtil.endOfDay(endOfMonth), "yyyy-MM-dd HH:mm:ss");
            dateList = DateUtil.rangeFunc(startOfMonth, endOfMonth, DateField.MONTH, date -> DateUtil.format(date, "yyyy-MM"));
            devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                    .eq(DeviceRelation::getProjectId, projectId)
                    .eq(DeviceRelation::getIsRealDevice, 1)
                    .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                    .isNotNull(DeviceRelation::getPropertyNo)
                    .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                    .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_DY.getType())
            );
        } else if (StatisticsType.STATISTICS_TYPE_MONTH.equals(groupType)) {
            intervals = "1d";
            DateTime dayDateTime = DateTime.of(datetime + "-01", "yyyy-MM-dd");
            DateTime startOfMonth = DateUtil.beginOfMonth(dayDateTime);
            DateTime endOfMonth = DateUtil.endOfMonth(dayDateTime);
            startTime = DateUtil.format(startOfMonth, "yyyy-MM-dd HH:mm:ss");
            endTime = DateUtil.format(endOfMonth, "yyyy-MM-dd HH:mm:ss");
            dateList = DateUtil.rangeFunc(startOfMonth, endOfMonth, DateField.DAY_OF_MONTH, date -> DateUtil.format(date, "yyyy-MM-dd"));
            devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                    .eq(DeviceRelation::getProjectId, projectId)
                    .eq(DeviceRelation::getIsRealDevice, 1)
                    .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                    .isNotNull(DeviceRelation::getPropertyNo)
                    .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                    .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_DR.getType())
            );
        } else {
            throw new ServiceException("暂不支持当前维度");
        }
        if (CollectionUtils.isEmpty(devicePropertyList)) {
            return Collections.emptyList();
        }
        List<String> sqlList = Lists.newArrayList();
        devicePropertyList.forEach(deviceProperty -> {
            String tableName = "property_" + projectId + "_" + deviceProperty.getDeviceId() + "_0";
            String sql = "("
                    + " SELECT " + deviceProperty.getDeviceId() + " AS deviceId, _wstart AS `time`, last_row(`" + deviceProperty.getPropertyNo() + "`) AS dataValue "
                    + " FROM " + tableName + " "
                    + " WHERE `time` >= '" + startTime + "' and `time` <= '" + endTime + "' "
                    + " interval(" + intervals + ")"
                    + ")";
            sqlList.add(sql);
        });
        List<DataValueVO> dataValueList = Lists.newArrayList();
        List<List<String>> partitionSqlList = Lists.partition(sqlList, 100);
        String dsTdengine = SystemConstant.DS_TDENGINE;
        for (List<String> stringList : partitionSqlList) {
            try {
                DynamicDataSourceContextHolder.push(dsTdengine);
                String currentDs = DynamicDataSourceContextHolder.peek();
                List<DataValueVO> currentDataValueList = iotDatasourceMapper.parseBean4TDengine(StrUtil.join(" UNION ALL ", stringList));
                if (CollectionUtils.isNotEmpty(currentDataValueList)) {
                    dataValueList.addAll(currentDataValueList);
                }
            } catch (Exception ex) {
                log.error("{}-发电量统计，异常", powerStationId == null ? "全站" : "子站", ex);
                throw new ServiceException((powerStationId == null ? "全站" : "子站") + "-发电量统计，操作数据源【" + dsTdengine + "】失败");
            } finally {
                DynamicDataSourceContextHolder.clear();
            }
        }
        log.info(JSON.toJSONString(dataValueList));
        Map<String, List<DataValueVO>> dataValueMap = dataValueList.stream().collect(Collectors.groupingBy(DataValueVO::getTime));
        Map<String, String> dataMap = Maps.newHashMap();
        dataValueMap.forEach((time, valueList) -> {
            BigDecimal totalSum = BigDecimal.ZERO;
            for (DataValueVO dataValueVO : valueList) {
                totalSum = totalSum.add(new BigDecimal(dataValueVO.getDataValue().toString()));
            }
            /*BigDecimal totalSum = valueList.stream().map(dataValueVO -> {
                BigDecimal bigDecimal = BigDecimal.ZERO;
                if (dataValueVO.getDataValue() != null) {
                    bigDecimal = new BigDecimal(dataValueVO.getDataValue().toString());
                }
                return bigDecimal;
            }).reduce(BigDecimal.ZERO, BigDecimal::add);*/
            if (StatisticsType.STATISTICS_TYPE_YEAR.equals(groupType)) {
                dataMap.put(time.substring(0, 7), totalSum.toPlainString());
            } else if (StatisticsType.STATISTICS_TYPE_MONTH.equals(groupType)) {
                dataMap.put(time.substring(0, 10), totalSum.toPlainString());
            }
        });
        for (String groupDate : dateList) {
            Map<String, String> tempMap = Maps.newTreeMap();
            tempMap.put("datetime", groupDate);
            tempMap.put("value", dataMap.get(groupDate));
            resultList.add(tempMap);
        }
        return resultList;
    }

    @Override
    public BigDecimal getDayElectricity(Long projectId, Long powerStationId, String datetime) {
        List<DeviceRelation> deviceList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getParentId, 0)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.SHU_CAI.getType())
        );
        if (CollectionUtils.isEmpty(deviceList)) {
            return BigDecimal.ZERO;
        }
        List<DeviceRelation> devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                .isNotNull(DeviceRelation::getPropertyNo)
                .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_DR.getType())
        );
        if (CollectionUtils.isEmpty(devicePropertyList)) {
            return BigDecimal.ZERO;
        }
        List<String> sqlList = Lists.newArrayList();
        devicePropertyList.forEach(deviceProperty -> {
            String tableName = "property_" + projectId + "_" + deviceProperty.getDeviceId() + "_0";
            String sql = "("
                    + " SELECT " + deviceProperty.getDeviceId() + " AS deviceId, last_row(`" + deviceProperty.getPropertyNo() + "`) AS dataValue "
                    + " FROM " + tableName + " "
                    + " WHERE `time` <= '" + datetime + " 23:59:59' "
                    + ")";
            sqlList.add(sql);
        });
        List<DataValueVO> dataValueList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        try {
            DynamicDataSourceContextHolder.push(dsTdengine);
            String currentDs = DynamicDataSourceContextHolder.peek();
            dataValueList = iotDatasourceMapper.parseBean4TDengine(StrUtil.join(" UNION ALL ", sqlList));
            log.info(JSON.toJSONString(dataValueList));
        } catch (Exception ex) {
            log.error("{}-某日发电量统计，异常", powerStationId == null ? "全站" : "子站", ex);
            throw new ServiceException((powerStationId == null ? "全站" : "子站") + "-某日发电量统计，操作数据源【" + dsTdengine + "】失败");
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
        BigDecimal totalSum = BigDecimal.ZERO;
        for (DataValueVO dataValueVO : dataValueList) {
            totalSum = totalSum.add(new BigDecimal(dataValueVO.getDataValue().toString()));
        }
        return totalSum;
    }

    @Override
    public BigDecimal getDayPower(Long projectId, Long powerStationId, String datetime) {
        List<DeviceRelation> deviceList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getParentId, 0)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.SHU_CAI.getType())
        );
        if (CollectionUtils.isEmpty(deviceList)) {
            return BigDecimal.ZERO;
        }
        List<DeviceRelation> devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                .isNotNull(DeviceRelation::getPropertyNo)
                .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_GL_YG.getType())
        );
        if (CollectionUtils.isEmpty(devicePropertyList)) {
            return BigDecimal.ZERO;
        }
        List<String> sqlList = Lists.newArrayList();
        devicePropertyList.forEach(deviceProperty -> {
            String tableName = "property_" + projectId + "_" + deviceProperty.getDeviceId() + "_0";
            String sql = "("
                    + " SELECT " + deviceProperty.getDeviceId() + " AS deviceId, last_row(`" + deviceProperty.getPropertyNo() + "`) AS dataValue "
                    + " FROM " + tableName + " "
                    + " WHERE `time` <= '" + datetime + " 23:59:59' "
                    + ")";
            sqlList.add(sql);
        });
        List<DataValueVO> dataValueList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        try {
            DynamicDataSourceContextHolder.push(dsTdengine);
            String currentDs = DynamicDataSourceContextHolder.peek();
            dataValueList = iotDatasourceMapper.parseBean4TDengine(StrUtil.join(" UNION ALL ", sqlList));
            log.info(JSON.toJSONString(dataValueList));
        } catch (Exception ex) {
            log.error("{}-某日有功功率，异常", powerStationId == null ? "全站" : "子站", ex);
            throw new ServiceException((powerStationId == null ? "全站" : "子站") + "-某日有功功率，操作数据源【" + dsTdengine + "】失败");
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
        BigDecimal totalSum = BigDecimal.ZERO;
        for (DataValueVO dataValueVO : dataValueList) {
            totalSum = totalSum.add(new BigDecimal(dataValueVO.getDataValue().toString()));
        }
        return totalSum;
    }

    @Override
    public BigDecimal getShuCaiPropertyValue(Long projectId, Long powerStationId, String queryType, String datetime) {
        List<DeviceRelation> deviceList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getParentId, 0)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.SHU_CAI.getType())
        );
        if (CollectionUtils.isEmpty(deviceList)) {
            return BigDecimal.ZERO;
        }
        LambdaQueryWrapper<DeviceRelation> queryWrapper = Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                .isNotNull(DeviceRelation::getPropertyNo)
                .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId);
        String tempTimeStr = DateUtil.now();
        String logStr = null;
        if (DevicePropertyTypeEnum.SC_FDL_DR.getType().equals(queryType)) {
            queryWrapper.eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_DR.getType());
            tempTimeStr = DateUtil.endOfDay(DateTime.of(datetime, "yyyy-MM-dd")).toString();
            logStr = "查询" + (powerStationId == null ? "全站" : "子站") + "当日发电量";
        } else if (DevicePropertyTypeEnum.SC_FDL_DY.getType().equals(queryType)) {
            queryWrapper.eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_DY.getType());
            tempTimeStr = DateUtil.endOfMonth(DateTime.of(datetime, "yyyy-MM")).toString();
            logStr = "查询" + (powerStationId == null ? "全站" : "子站") + "当月发电量";
        } else if (DevicePropertyTypeEnum.SC_FDL_DN.getType().equals(queryType)) {
            queryWrapper.eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_DN.getType());
            tempTimeStr = DateUtil.endOfMonth(DateTime.of(datetime + "-12", "yyyy-MM")).toString();
            logStr = "查询" + (powerStationId == null ? "全站" : "子站") + "当年发电量";
        } else if (DevicePropertyTypeEnum.SC_FDL_LJ.getType().equals(queryType)) {
            queryWrapper.eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_LJ.getType());
            tempTimeStr = DateUtil.endOfDay(DateTime.of(datetime, "yyyy-MM-dd")).toString();
            logStr = "查询" + (powerStationId == null ? "全站" : "子站") + "累计发电量";
        } else if (DevicePropertyTypeEnum.SC_GL_YG.getType().equals(queryType)) {
            queryWrapper.eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_GL_YG.getType());
            tempTimeStr = DateUtil.endOfDay(DateTime.of(datetime, "yyyy-MM-dd")).toString();
            logStr = "查询" + (powerStationId == null ? "全站" : "子站") + "当日有功功率";
        } else if (DevicePropertyTypeEnum.SC_GL_WG.getType().equals(queryType)) {
            queryWrapper.eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_GL_WG.getType());
            tempTimeStr = DateUtil.endOfDay(DateTime.of(datetime, "yyyy-MM-dd")).toString();
            logStr = "查询" + (powerStationId == null ? "全站" : "子站") + "当日无功功率";
        } else {
            throw new ServiceException("暂不支持" + queryType + "类型的统计查询");
        }
        List<DeviceRelation> devicePropertyList = deviceRelationMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(devicePropertyList)) {
            return BigDecimal.ZERO;
        }
        List<String> sqlList = Lists.newArrayList();
        String finalQueryTimeStr = tempTimeStr;
        devicePropertyList.forEach(deviceProperty -> {
            String tableName = "property_" + projectId + "_" + deviceProperty.getDeviceId() + "_0";
            String sql = "("
                    + " SELECT " + deviceProperty.getDeviceId() + " AS deviceId, last_row(`" + deviceProperty.getPropertyNo() + "`) AS dataValue "
                    + " FROM " + tableName + " "
                    + " WHERE `time` <= '" + finalQueryTimeStr + "' "
                    + ")";
            sqlList.add(sql);
        });
        List<DataValueVO> dataValueList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        try {
            DynamicDataSourceContextHolder.push(dsTdengine);
            String currentDs = DynamicDataSourceContextHolder.peek();
            dataValueList = iotDatasourceMapper.parseBean4TDengine(StrUtil.join(" UNION ALL ", sqlList));
            log.info(JSON.toJSONString(dataValueList));
        } catch (Exception ex) {
            log.error("{}，异常", logStr, ex);
            throw new ServiceException(logStr + "，操作数据源【" + dsTdengine + "】失败");
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
        BigDecimal totalSum = BigDecimal.ZERO;
        for (DataValueVO dataValueVO : dataValueList) {
            totalSum = totalSum.add(new BigDecimal(dataValueVO.getDataValue().toString()));
        }
        return totalSum;
    }

    @Override
    public List<Map<String, String>> generateElectricity4Xb(Long projectId, Long powerStationId, String groupType, String datetime) {
        List<DeviceRelation> deviceList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getParentId, 0)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.SHU_CAI.getType())
                .orderByAsc(DeviceRelation::getId)
        );
        if (CollectionUtils.isEmpty(deviceList)) {
            return Collections.emptyList();
        }
        List<DeviceRelation> devicePropertyList = Lists.newArrayList();
        List<Map<String, String>> resultList = Lists.newArrayList();
        String startTime, endTime;
        if (StatisticsType.STATISTICS_TYPE_MONTH.equals(groupType)) {
            DateTime dayDateTime = DateTime.of(datetime + "-01", "yyyy-MM-dd");
            startTime = DateUtil.format(DateUtil.beginOfMonth(dayDateTime), "yyyy-MM-dd HH:mm:ss");
            endTime = DateUtil.format(DateUtil.endOfMonth(dayDateTime), "yyyy-MM-dd HH:mm:ss");
            devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                    .eq(DeviceRelation::getProjectId, projectId)
                    .eq(DeviceRelation::getIsRealDevice, 1)
                    .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                    .isNotNull(DeviceRelation::getPropertyNo)
                    .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                    .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_DY.getType())
            );
        } else if (StatisticsType.STATISTICS_TYPE_DAY.equals(groupType)) {
            DateTime dayDateTime = DateTime.of(datetime, "yyyy-MM-dd");
            startTime = DateUtil.format(DateUtil.beginOfDay(dayDateTime), "yyyy-MM-dd HH:mm:ss");
            endTime = DateUtil.format(DateUtil.endOfDay(dayDateTime), "yyyy-MM-dd HH:mm:ss");
            devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                    .eq(DeviceRelation::getProjectId, projectId)
                    .eq(DeviceRelation::getIsRealDevice, 1)
                    .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                    .isNotNull(DeviceRelation::getPropertyNo)
                    .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                    .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_FDL_DR.getType())
            );
        } else {
            throw new ServiceException("暂不支持当前维度");
        }
        if (CollectionUtils.isEmpty(devicePropertyList)) {
            return Collections.emptyList();
        }
        List<String> sqlList = Lists.newArrayList();
        devicePropertyList.forEach(deviceProperty -> {
            String tableName = "property_" + projectId + "_" + deviceProperty.getDeviceId() + "_0";
            String sql = "("
                    + " SELECT " + deviceProperty.getDeviceId() + " AS deviceId, _wstart AS `time`, last_row(`" + deviceProperty.getPropertyNo() + "`) AS dataValue "
                    + " FROM " + tableName + " "
                    + " WHERE `time` >= '" + startTime + "' and `time` <= '" + endTime + "' "
                    + ")";
            sqlList.add(sql);
        });
        List<DataValueVO> dataValueList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        try {
            DynamicDataSourceContextHolder.push(dsTdengine);
            String currentDs = DynamicDataSourceContextHolder.peek();
            dataValueList = iotDatasourceMapper.parseBean4TDengine(StrUtil.join(" UNION ALL ", sqlList));
            log.info(JSON.toJSONString(dataValueList));
        } catch (Exception ex) {
            log.error("发电分析-电站下的箱变，异常", ex);
            throw new ServiceException("发电分析-电站下的箱变，操作数据源【" + dsTdengine + "】失败");
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
        Map<String, DataValueVO> deviceNameMap = dataValueList.stream().collect(Collectors.toMap(DataValueVO::getDeviceId, e -> e));
        for (DeviceRelation deviceRelation : deviceList) {
            Map<String, String> tempMap = Maps.newTreeMap();
            tempMap.put("name", deviceRelation.getName());
            DataValueVO dataValueVO = deviceNameMap.get(deviceRelation.getDeviceId().toString());
            if (dataValueVO != null) {
                tempMap.put("datetime", dataValueVO.getTime());
                tempMap.put("value", dataValueVO.getDataValue());
            }
            resultList.add(tempMap);
        }
        return resultList;
    }

    @Override
    public List<Map<String, String>> generateElectricity4Nbq(Long projectId, Long powerStationId, Long xbDeviceId, String groupType, String datetime) {
        List<DeviceRelation> deviceList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getParentId, xbDeviceId)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.NI_BIAN_QI.getType())
                .orderByAsc(DeviceRelation::getId)
        );
        if (CollectionUtils.isEmpty(deviceList)) {
            return Collections.emptyList();
        }
        List<DeviceRelation> devicePropertyList = Lists.newArrayList();
        List<Map<String, String>> resultList = Lists.newArrayList();
        String startTime, endTime;
        if (StatisticsType.STATISTICS_TYPE_MONTH.equals(groupType)) {
            DateTime dayDateTime = DateTime.of(datetime + "-01", "yyyy-MM-dd");
            startTime = DateUtil.format(DateUtil.beginOfMonth(dayDateTime), "yyyy-MM-dd HH:mm:ss");
            endTime = DateUtil.format(DateUtil.endOfMonth(dayDateTime), "yyyy-MM-dd HH:mm:ss");
            devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                    .eq(DeviceRelation::getProjectId, projectId)
                    .eq(DeviceRelation::getIsRealDevice, 1)
                    .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                    .isNotNull(DeviceRelation::getPropertyNo)
                    .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                    .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.NBQ_FDL_DY.getType())
            );
        } else if (StatisticsType.STATISTICS_TYPE_DAY.equals(groupType)) {
            DateTime dayDateTime = DateTime.of(datetime, "yyyy-MM-dd");
            startTime = DateUtil.format(DateUtil.beginOfDay(dayDateTime), "yyyy-MM-dd HH:mm:ss");
            endTime = DateUtil.format(DateUtil.endOfDay(dayDateTime), "yyyy-MM-dd HH:mm:ss");
            devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                    .eq(DeviceRelation::getProjectId, projectId)
                    .eq(DeviceRelation::getIsRealDevice, 1)
                    .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                    .isNotNull(DeviceRelation::getPropertyNo)
                    .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                    .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.NBQ_FDL_DR.getType())
            );
        } else {
            throw new ServiceException("暂不支持当前维度");
        }
        if (CollectionUtils.isEmpty(devicePropertyList)) {
            return Collections.emptyList();
        }
        List<String> sqlList = Lists.newArrayList();
        devicePropertyList.forEach(deviceProperty -> {
            String tableName = "property_" + projectId + "_" + deviceProperty.getDeviceId() + "_0";
            String sql = "("
                    + " SELECT " + deviceProperty.getDeviceId() + " AS deviceId, _wstart AS `time`, last_row(`" + deviceProperty.getPropertyNo() + "`) AS dataValue "
                    + " FROM " + tableName + " "
                    + " WHERE `time` >= '" + startTime + "' and `time` <= '" + endTime + "' "
                    + ")";
            sqlList.add(sql);
        });
        List<DataValueVO> dataValueList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        try {
            DynamicDataSourceContextHolder.push(dsTdengine);
            String currentDs = DynamicDataSourceContextHolder.peek();
            dataValueList = iotDatasourceMapper.parseBean4TDengine(StrUtil.join(" UNION ALL ", sqlList));
            log.info(JSON.toJSONString(dataValueList));
        } catch (Exception ex) {
            log.error("发电分析-箱变下的逆变器，异常", ex);
            throw new ServiceException("发电分析-箱变下的逆变器，操作数据源【" + dsTdengine + "】失败");
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
        Map<String, DataValueVO> deviceNameMap = dataValueList.stream().collect(Collectors.toMap(DataValueVO::getDeviceId, e -> e));
        for (DeviceRelation deviceRelation : deviceList) {
            Map<String, String> tempMap = Maps.newTreeMap();
            tempMap.put("name", deviceRelation.getName());
            DataValueVO dataValueVO = deviceNameMap.get(deviceRelation.getDeviceId().toString());
            if (dataValueVO != null) {
                tempMap.put("datetime", dataValueVO.getTime());
                tempMap.put("value", dataValueVO.getDataValue());
            }
            resultList.add(tempMap);
        }
        return resultList;
    }

    @Override
    public List<Map<String, String>> powerStatistics(Long projectId, Long powerStationId, String datetime) {
        List<DeviceRelation> deviceList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getParentId, 0)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.SHU_CAI.getType())
        );
        if (CollectionUtils.isEmpty(deviceList)) {
            return Collections.emptyList();
        }
        List<Map<String, String>> resultList = Lists.newArrayList();
        String intervals = "1h";
        DateTime dayDateTime = DateTime.of(datetime, "yyyy-MM-dd");
        DateTime startOfDay = DateUtil.beginOfDay(dayDateTime);
        DateTime endOfDay = DateUtil.endOfDay(dayDateTime);
        String startTime = DateUtil.format(startOfDay, "yyyy-MM-dd HH:mm:ss");
        String endTime = DateUtil.format(endOfDay, "yyyy-MM-dd HH:mm:ss");
        List<String> dateList = DateUtil.rangeFunc(startOfDay, endOfDay, DateField.HOUR_OF_DAY, date -> DateUtil.format(date, "yyyy-MM-dd HH:mm"));
        List<DeviceRelation> devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                .isNotNull(DeviceRelation::getPropertyNo)
                .eq(powerStationId != null, DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_GL_YG.getType())
        );
        if (CollectionUtils.isEmpty(devicePropertyList)) {
            return Collections.emptyList();
        }
        List<String> sqlList = Lists.newArrayList();
        devicePropertyList.forEach(deviceProperty -> {
            String tableName = "property_" + projectId + "_" + deviceProperty.getDeviceId() + "_0";
            String sql = "("
                    + " SELECT " + deviceProperty.getDeviceId() + " AS deviceId, _wstart AS `time`, last_row(`" + deviceProperty.getPropertyNo() + "`) AS dataValue "
                    + " FROM " + tableName + " "
                    + " WHERE `time` >= '" + startTime + "' and `time` <= '" + endTime + "' "
                    + " interval(" + intervals + ")"
                    + ")";
            sqlList.add(sql);
        });
        List<DataValueVO> dataValueList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        try {
            DynamicDataSourceContextHolder.push(dsTdengine);
            String currentDs = DynamicDataSourceContextHolder.peek();
            List<DataValueVO> currentDataValueList = iotDatasourceMapper.parseBean4TDengine(StrUtil.join(" UNION ALL ", sqlList));
            if (CollectionUtils.isNotEmpty(currentDataValueList)) {
                dataValueList.addAll(currentDataValueList);
            }
        } catch (Exception ex) {
            log.error("{}-功率统计异常", powerStationId == null ? "全站" : "子站", ex);
            throw new ServiceException((powerStationId == null ? "全站" : "子站") + "-功率统计，操作数据源【" + dsTdengine + "】失败");
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
        log.info(JSON.toJSONString(dataValueList));
        Map<String, List<DataValueVO>> dataValueMap = dataValueList.stream().collect(Collectors.groupingBy(DataValueVO::getTime));
        Map<String, String> dataMap = Maps.newHashMap();
        dataValueMap.forEach((time, valueList) -> {
            BigDecimal totalSum = BigDecimal.ZERO;
            for (DataValueVO dataValueVO : valueList) {
                totalSum = totalSum.add(new BigDecimal(dataValueVO.getDataValue().toString()));
            }
            /*BigDecimal totalSum = valueList.stream().map(dataValueVO -> {
                BigDecimal bigDecimal = BigDecimal.ZERO;
                if (dataValueVO.getDataValue() != null) {
                    bigDecimal = new BigDecimal(dataValueVO.getDataValue().toString());
                }
                return bigDecimal;
            }).reduce(BigDecimal.ZERO, BigDecimal::add);*/
            dataMap.put(time.substring(0, 16), totalSum.toPlainString());
        });
        for (String groupDate : dateList) {
            Map<String, String> tempMap = Maps.newTreeMap();
            tempMap.put("datetime", groupDate);
            tempMap.put("value", dataMap.get(groupDate));
            resultList.add(tempMap);
        }
        return resultList;
    }

    @Override
    public List<Map<String, String>> powerStatistics4Xb(Long projectId, Long powerStationId, Long deviceRelationId, String datetime) {
        DeviceRelation deviceProperty = deviceRelationMapper.selectOne(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(DeviceRelation::getParentId, deviceRelationId)
                .isNotNull(DeviceRelation::getPropertyNo)
                .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.SC_GL_YG.getType())
                .orderByDesc(DeviceRelation::getId)
                .last("limit 1")
        );
        if (deviceProperty == null) {
            return Collections.emptyList();
        }
        List<Map<String, String>> resultList = Lists.newArrayList();
        String intervals = "1h";
        DateTime dayDateTime = DateTime.of(datetime, "yyyy-MM-dd");
        DateTime startOfDay = DateUtil.beginOfDay(dayDateTime);
        DateTime endOfDay = DateUtil.endOfDay(dayDateTime);
        String startTime = DateUtil.format(startOfDay, "yyyy-MM-dd HH:mm:ss");
        String endTime = DateUtil.format(endOfDay, "yyyy-MM-dd HH:mm:ss");
        List<String> dateList = DateUtil.rangeFunc(startOfDay, endOfDay, DateField.HOUR_OF_DAY, date -> DateUtil.format(date, "yyyy-MM-dd HH:mm"));
        String tableName = "property_" + projectId + "_" + deviceProperty.getDeviceId() + "_0";
        String sql = "SELECT " + deviceProperty.getDeviceId() + " AS deviceId, _wstart AS `time`, last_row(`" + deviceProperty.getPropertyNo() + "`) AS dataValue "
                + " FROM " + tableName + " "
                + " WHERE `time` >= '" + startTime + "' and `time` <= '" + endTime + "' "
                + " interval(" + intervals + ")";
        List<DataValueVO> dataValueList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        try {
            DynamicDataSourceContextHolder.push(dsTdengine);
            String currentDs = DynamicDataSourceContextHolder.peek();
            dataValueList = iotDatasourceMapper.parseBean4TDengine(sql);
        } catch (Exception ex) {
            log.error("箱变-功率统计，异常", ex);
            throw new ServiceException("箱变-功率统计，操作数据源【" + dsTdengine + "】失败");
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
        log.info(JSON.toJSONString(dataValueList));
        Map<String, String> dataMap = Maps.newHashMap();
        dataValueList.forEach(dataValueVO -> {
            dataMap.put(dataValueVO.getTime().substring(0, 16), dataValueVO.getDataValue());
        });
        for (String groupDate : dateList) {
            Map<String, String> tempMap = Maps.newTreeMap();
            tempMap.put("datetime", groupDate);
            tempMap.put("value", dataMap.get(groupDate));
            resultList.add(tempMap);
        }
        return resultList;
    }

    @Override
    public List<Map<String, String>> powerStatistics4Nbq(Long projectId, Long powerStationId, Long deviceRelationId, String datetime) {
        DeviceRelation deviceProperty = deviceRelationMapper.selectOne(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(DeviceRelation::getParentId, deviceRelationId)
                .isNotNull(DeviceRelation::getPropertyNo)
                .eq(DeviceRelation::getPropertyType, DevicePropertyTypeEnum.NBQ_GL_YG.getType())
                .orderByDesc(DeviceRelation::getId)
                .last("limit 1")
        );
        if (deviceProperty == null) {
            return Collections.emptyList();
        }
        List<Map<String, String>> resultList = Lists.newArrayList();
        String intervals = "1h";
        DateTime dayDateTime = DateTime.of(datetime, "yyyy-MM-dd");
        DateTime startOfDay = DateUtil.beginOfDay(dayDateTime);
        DateTime endOfDay = DateUtil.endOfDay(dayDateTime);
        String startTime = DateUtil.format(startOfDay, "yyyy-MM-dd HH:mm:ss");
        String endTime = DateUtil.format(endOfDay, "yyyy-MM-dd HH:mm:ss");
        List<String> dateList = DateUtil.rangeFunc(startOfDay, endOfDay, DateField.HOUR_OF_DAY, date -> DateUtil.format(date, "yyyy-MM-dd HH:mm"));
        String tableName = "property_" + projectId + "_" + deviceProperty.getDeviceId() + "_0";
        String sql = "SELECT " + deviceProperty.getDeviceId() + " AS deviceId, _wstart AS `time`, last_row(`" + deviceProperty.getPropertyNo() + "`) AS dataValue "
                + " FROM " + tableName + " "
                + " WHERE `time` >= '" + startTime + "' and `time` <= '" + endTime + "' "
                + " interval(" + intervals + ")";
        List<DataValueVO> dataValueList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        try {
            DynamicDataSourceContextHolder.push(dsTdengine);
            String currentDs = DynamicDataSourceContextHolder.peek();
            dataValueList = iotDatasourceMapper.parseBean4TDengine(sql);
        } catch (Exception ex) {
            log.error("逆变器-功率统计，异常", ex);
            throw new ServiceException("逆变器-功率统计，操作数据源【" + dsTdengine + "】失败");
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
        log.info(JSON.toJSONString(dataValueList));
        Map<String, String> dataMap = Maps.newHashMap();
        dataValueList.forEach(dataValueVO -> {
            dataMap.put(dataValueVO.getTime().substring(0, 16), dataValueVO.getDataValue());
        });
        for (String groupDate : dateList) {
            Map<String, String> tempMap = Maps.newTreeMap();
            tempMap.put("datetime", groupDate);
            tempMap.put("value", dataMap.get(groupDate));
            resultList.add(tempMap);
        }
        return resultList;
    }

    @Override
    public Map<String, List<MpptPvVO>> dispersionRatioAnalyse4Mppt(Long projectId, Long powerStationId, Long deviceRelationId, String datetime) {
        List<DeviceRelation> deviceList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getParentId, deviceRelationId)
                .eq(DeviceRelation::getIsRealDevice, 0)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.NI_BIAN_QI_MPPT_PV.getType())
                .isNull(DeviceRelation::getPropertyNo)
                .orderByAsc(DeviceRelation::getId)
        );
        if (CollectionUtils.isEmpty(deviceList)) {
            return Collections.emptyMap();
        }
        Map<Long, DeviceRelation> pvDeviceMap = Maps.newTreeMap();
        for (DeviceRelation deviceRelation : deviceList) {
            pvDeviceMap.put(deviceRelation.getId(), deviceRelation);
        }
        List<DeviceRelation> devicePropertyList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getPowerStationId, powerStationId)
                .in(DeviceRelation::getParentId, deviceList.stream().map(DeviceRelation::getId).toList())
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.NI_BIAN_QI_MPPT_PV.getType())
                .isNotNull(DeviceRelation::getPropertyNo)
                .orderByAsc(DeviceRelation::getDeviceId)
                .orderByAsc(DeviceRelation::getId)
        );
        if (CollectionUtils.isEmpty(devicePropertyList)) {
            return Collections.emptyMap();
        }
        List<Long> deviceIdList = devicePropertyList.stream().map(DeviceRelation::getDeviceId).distinct().toList();
        if (deviceIdList.size() != 1) {
            throw new ServiceException("MPPT组串关系绑定错误(不在同一个逆变器设备下)");
        }
        Map<String, String> devicePropertyMap = Maps.newHashMap();
        devicePropertyList.forEach(deviceProperty -> {
            devicePropertyMap.put(deviceProperty.getParentId() + "_" + deviceProperty.getPropertyType(), deviceProperty.getPropertyNo());
        });
        List<MpptPvDTO> mpptPvDTOList = Lists.newArrayList();
        deviceList.forEach(deviceRelation -> {
            Long parentId = deviceRelation.getId();
            MpptPvDTO mpptPvDTO = new MpptPvDTO();
            mpptPvDTO.setParentId(parentId);
            String dyKey = parentId + "_" + DevicePropertyTypeEnum.NBQ_PV_DY.getType();
            if (devicePropertyMap.containsKey(dyKey)) {
                mpptPvDTO.setDy(devicePropertyMap.get(dyKey));
            }
            String dlKey = parentId + "_" + DevicePropertyTypeEnum.NBQ_PV_DL.getType();
            if (devicePropertyMap.containsKey(dlKey)) {
                mpptPvDTO.setDl(devicePropertyMap.get(dlKey));
            }
            if (StringUtils.isNotBlank(mpptPvDTO.getDy()) && StringUtils.isNotBlank(mpptPvDTO.getDl())) {
                mpptPvDTOList.add(mpptPvDTO);
            }
        });
        if (mpptPvDTOList.size() != deviceList.size()) {
            throw new ServiceException("MPPT组串关系绑定错误(电压、电流数量不对应)");
        }
        List<String> selectSqlList = Lists.newArrayList();
        mpptPvDTOList.forEach(mpptPvDTO -> {
            String paramSql = "last_row(`" + mpptPvDTO.getDy() + "`) AS dy_" + mpptPvDTO.getParentId()
                    + ", last_row(`" + mpptPvDTO.getDl() + "`) AS dl_" + mpptPvDTO.getParentId();
            selectSqlList.add(paramSql);
        });
        String intervals = "1h";
        DateTime dayDateTime = DateTime.of(datetime, "yyyy-MM-dd");
        DateTime startOfDay = DateUtil.beginOfDay(dayDateTime);
        DateTime endOfDay = DateUtil.endOfDay(dayDateTime);
        String startTime = DateUtil.format(startOfDay, "yyyy-MM-dd HH:mm:ss");
        String endTime = DateUtil.format(endOfDay, "yyyy-MM-dd HH:mm:ss");
        List<String> dateList = DateUtil.rangeFunc(startOfDay, endOfDay, DateField.HOUR_OF_DAY, date -> DateUtil.format(date, "yyyy-MM-dd HH:mm"));
        String tableName = "property_" + projectId + "_" + deviceIdList.get(0) + "_0";
        String sql = "SELECT _wstart AS `time`, " + StrUtil.join(", ", selectSqlList)
                + " FROM " + tableName + " "
                + " WHERE `time` >= '" + startTime + "' and `time` <= '" + endTime + "' "
                + " interval(" + intervals + ")";
        List<LinkedHashMap<String, Object>> dataValueList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        try {
            DynamicDataSourceContextHolder.push(dsTdengine);
            String currentDs = DynamicDataSourceContextHolder.peek();
            dataValueList = iotDatasourceMapper.parseListMap4TDengine(sql);
        } catch (Exception ex) {
            log.error("组串离散率分析，异常", ex);
            throw new ServiceException("组串离散率分析，操作数据源【" + dsTdengine + "】失败");
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
        log.info(JSON.toJSONString(dataValueList));
        Map<String, Object> dataMap = Maps.newHashMap();
        dataValueList.forEach(dataValueMap -> {
            if (dataValueMap.get("time") != null) {
                String timeString = dataValueMap.get("time").toString();
                dataValueMap.forEach((pointKey, pointValue) -> {
                    if (!"time".equals(pointKey)) {
                        dataMap.put(pointKey + "_" + timeString.substring(0, 16), new BigDecimal(pointValue.toString()));
                    }
                });
            }
        });
        Map<String, List<MpptPvVO>> resultMap = Maps.newTreeMap();
        pvDeviceMap.forEach((relationId, relation) -> {
            List<MpptPvVO> dataList = Lists.newArrayList();
            for (String groupDate : dateList) {
                MpptPvVO mpptPvVO = new MpptPvVO();
                mpptPvVO.setDatetime(groupDate);
                mpptPvVO.setName(relation.getName());
                Object dyObj = null;
                if (dataMap.containsKey("dy_" + relationId + "_" + groupDate)) {
                    dyObj = dataMap.get("dy_" + relationId + "_" + groupDate);
                    mpptPvVO.setDy(dyObj.toString());
                }
                Object dlObj = null;
                if (dataMap.containsKey("dl_" + relationId + "_" + groupDate)) {
                    dlObj = dataMap.get("dl_" + relationId + "_" + groupDate);
                    mpptPvVO.setDl(dlObj.toString());
                }
                if (dyObj != null && dlObj != null) {
                    String powerString = NumberUtil.mul(new BigDecimal(dyObj.toString()), new BigDecimal(dlObj.toString())).toPlainString();
                    mpptPvVO.setPower(powerString);
                }
                dataList.add(mpptPvVO);
            }
            resultMap.put(relation.getName(), dataList);
        });
        return resultMap;
    }

    @Override
    public List<DeviceRelationWithPropertyValueVO> nbqPropertyValueList(Long projectId, Long powerStationId, Long nbqDeviceRelationId) {
        List<DeviceRelation> deviceRelationList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getParentId, nbqDeviceRelationId)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.NI_BIAN_QI.getType())
                .isNotNull(DeviceRelation::getPropertyNo));
        if (CollectionUtils.isEmpty(deviceRelationList)) {
            return Collections.emptyList();
        }
        List<DeviceRelationWithPropertyValueVO> withPropertyValueList = Lists.newArrayList();
        List<String> selectSqlList = Lists.newArrayList();
        deviceRelationList.forEach(deviceRelation -> {
            DeviceRelationWithPropertyValueVO propertyValueVO = new DeviceRelationWithPropertyValueVO();
            BeanUtils.copyProperties(deviceRelation, propertyValueVO);
            withPropertyValueList.add(propertyValueVO);

            String paramSql = "last_row(`" + deviceRelation.getPropertyNo() + "`) AS data_" + deviceRelation.getId();
            selectSqlList.add(paramSql);
        });
        String tableName = "property_" + projectId + "_" + deviceRelationList.get(0).getDeviceId() + "_0";
        String sql = "SELECT " + StrUtil.join(", ", selectSqlList)
                + " FROM " + tableName;
        List<LinkedHashMap<String, Object>> dataValueList = Lists.newArrayList();
        String dsTdengine = SystemConstant.DS_TDENGINE;
        try {
            DynamicDataSourceContextHolder.push(dsTdengine);
            String currentDs = DynamicDataSourceContextHolder.peek();
            dataValueList = iotDatasourceMapper.parseListMap4TDengine(sql);
        } catch (Exception ex) {
            log.error("查询某个逆变器的点位实时采集值，异常", ex);
            throw new ServiceException("查询某个逆变器的点位实时采集值，操作数据源【" + dsTdengine + "】失败");
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
        log.info(JSON.toJSONString(dataValueList));
        Map<String, Object> dataMap = Maps.newHashMap();
        dataValueList.forEach(dataValueMap ->
                dataValueMap.forEach((pointKey, pointValue) ->
                        dataMap.put(pointKey.replace("data_", ""), pointValue)
                )
        );
        withPropertyValueList.forEach(withPropertyValueVO -> {
            String idString = withPropertyValueVO.getId().toString();
            if (dataMap.containsKey(idString)) {
                withPropertyValueVO.setPropertyValue(dataMap.get(idString).toString());
            }
        });
        return withPropertyValueList;
    }

    @Override
    public List<Tree<String>> mpptPvTreeList(Long projectId, Long powerStationId, Long nbqDeviceRelationId) {
        DeviceRelation nbqDeviceRelation = deviceRelationMapper.selectOne(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getId, nbqDeviceRelationId)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.NI_BIAN_QI.getType()));
        if (nbqDeviceRelation == null) {
            return Collections.emptyList();
        }
        Long nbqDeviceId = nbqDeviceRelation.getDeviceId();
        List<DeviceRelation> deviceRelationList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getDeviceId, nbqDeviceId)
                .in(DeviceRelation::getDeviceType, Arrays.asList(DeviceTypeEnum.NI_BIAN_QI_MPPT.getType(), DeviceTypeEnum.NI_BIAN_QI_MPPT_PV.getType())));
        if (CollectionUtils.isEmpty(deviceRelationList)) {
            return Collections.emptyList();
        }
        Set<Long> deviceIdSet = deviceRelationList.stream().map(DeviceRelation::getDeviceId).collect(Collectors.toSet());
        if (deviceIdSet.size() != 1) {
            throw new ServiceException("MPPT组串关系绑定错误(点位不属于同一个逆变器设备)");
        }
        List<DeviceRelationWithPropertyValueVO> withPropertyValueList = Lists.newArrayList();
        deviceRelationList.forEach(deviceRelation -> {
            DeviceRelationWithPropertyValueVO propertyValueVO = new DeviceRelationWithPropertyValueVO();
            BeanUtils.copyProperties(deviceRelation, propertyValueVO);
            withPropertyValueList.add(propertyValueVO);
        });
        List<DeviceRelation> pvPropertyList = deviceRelationList.stream()
                .filter(deviceRelation -> StringUtils.isNotBlank(deviceRelation.getPropertyNo()))
                .collect(Collectors.toUnmodifiableList());
        if (CollectionUtils.isNotEmpty(pvPropertyList)) {
            List<String> selectSqlList = Lists.newArrayList();
            pvPropertyList.forEach(pvProperty -> {
                String paramSql = "last_row(`" + pvProperty.getPropertyNo() + "`) AS data_" + pvProperty.getId();
                selectSqlList.add(paramSql);
            });
            String tableName = "property_" + projectId + "_" + nbqDeviceId + "_0";
            String sql = "SELECT " + StrUtil.join(", ", selectSqlList)
                    + " FROM " + tableName;
            List<LinkedHashMap<String, Object>> dataValueList = Lists.newArrayList();
            String dsTdengine = SystemConstant.DS_TDENGINE;
            try {
                DynamicDataSourceContextHolder.push(dsTdengine);
                String currentDs = DynamicDataSourceContextHolder.peek();
                dataValueList = iotDatasourceMapper.parseListMap4TDengine(sql);
            } catch (Exception ex) {
                log.error("查询某个逆变器下的MPPT、PV树结构及实时采集值，异常", ex);
                throw new ServiceException("查询某个逆变器下的MPPT、PV树结构及实时采集值，操作数据源【" + dsTdengine + "】失败");
            } finally {
                DynamicDataSourceContextHolder.clear();
            }
            log.info(JSON.toJSONString(dataValueList));
            Map<String, Object> dataMap = Maps.newHashMap();
            dataValueList.forEach(dataValueMap ->
                    dataValueMap.forEach((pointKey, pointValue) ->
                            dataMap.put(pointKey.replace("data_", ""), pointValue)
                    )
            );
            withPropertyValueList.forEach(withPropertyValueVO -> {
                String idString = withPropertyValueVO.getId().toString();
                if (dataMap.containsKey(idString)) {
                    withPropertyValueVO.setPropertyValue(dataMap.get(idString).toString());
                }
            });
        }
        return this.buildDeviceRelationTree(withPropertyValueList, String.valueOf(nbqDeviceRelationId));
    }

    @Override
    public List<ElectricMeterValueVO> dbPropertyValueList(Long projectId, Long powerStationId) {
        List<ElectricMeterValueVO> electricMeterValueList = Lists.newArrayList();
        // 查询电站下的所有电表
        List<DeviceRelation> dbDeviceList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getPowerStationId, powerStationId)
                .eq(DeviceRelation::getParentId, 0)
                .eq(DeviceRelation::getIsRealDevice, 1)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.DIAN_BIAO.getType()));
        if (CollectionUtils.isEmpty(dbDeviceList)) {
            return electricMeterValueList;
        }
        // 查询所有电表的测量点
        List<DeviceRelation> dbcldDeviceList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                .eq(DeviceRelation::getProjectId, projectId)
                .eq(DeviceRelation::getPowerStationId, powerStationId)
                .in(DeviceRelation::getParentId, dbDeviceList.stream().map(DeviceRelation::getId).toList())
                .eq(DeviceRelation::getIsRealDevice, 0)
                .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.DIAN_BIAO_CLD.getType())
        );
        if (CollectionUtils.isEmpty(dbcldDeviceList)) {
            return electricMeterValueList;
        }
        // 查询每个测量点的采集点及其采集值
        dbcldDeviceList.forEach(dbcldDevice -> {
            List<DeviceRelation> deviceRelationList = deviceRelationMapper.selectList(Wrappers.lambdaQuery(DeviceRelation.class)
                    .eq(DeviceRelation::getProjectId, projectId)
                    .eq(DeviceRelation::getPowerStationId, powerStationId)
                    .eq(DeviceRelation::getParentId, dbcldDevice.getId())
                    .eq(DeviceRelation::getIsRealDevice, 1)
                    .eq(DeviceRelation::getDeviceType, DeviceTypeEnum.DIAN_BIAO_CLD.getType())
                    .isNotNull(DeviceRelation::getPropertyNo));
            if (CollectionUtils.isNotEmpty(deviceRelationList)) {
                Map<String, String> devicePropertyMap = Maps.newHashMap();
                deviceRelationList.forEach(deviceProperty -> {
                    devicePropertyMap.put(deviceProperty.getParentId() + "_" + deviceProperty.getPropertyType(), deviceProperty.getPropertyNo());
                });
                Map<String, String> meterPropertyMap = Maps.newHashMap();
                deviceRelationList.forEach(dbcld -> {
                    Long parentId = dbcld.getParentId();
                    meterPropertyMap.put(dbcld.getPropertyNo(), dbcld.getPropertyType() + "_" + parentId);
                });
                List<String> selectSqlList = Lists.newArrayList();
                meterPropertyMap.forEach((column, alias) -> {
                    String paramSql = "`" + column + "` AS " + alias;
                    selectSqlList.add(paramSql);
                });
                String tableName = "property_" + projectId + "_" + dbcldDevice.getDeviceId() + "_0";
                String sql = "SELECT `time` AS time, " + StrUtil.join(", ", selectSqlList)
                        + " FROM " + tableName
                        + " ORDER BY `time` DESC "
                        + " LIMIT 1";
                String dsTdengine = SystemConstant.DS_TDENGINE;
                try {
                    DynamicDataSourceContextHolder.push(dsTdengine);
                    String currentDs = DynamicDataSourceContextHolder.peek();
                    HashMap<String, Object> dataValueMap = iotDatasourceMapper.parseMap4TDengine(sql);
                    ElectricMeterValueVO electricMeterValueVO = new ElectricMeterValueVO();
                    electricMeterValueVO.setProjectId(projectId);
                    electricMeterValueVO.setPowerStationId(powerStationId);
                    electricMeterValueVO.setPowerStationName("");
                    electricMeterValueVO.setPointName(dbcldDevice.getName());
                    electricMeterValueVO.setTime(dataValueMap.get("time").toString());
                    electricMeterValueVO.setZxygz(dataValueMap.get(DevicePropertyTypeEnum.DB_ZXYGZ.getType() + "_" + dbcldDevice.getId()).toString());
                    electricMeterValueVO.setFxygz(dataValueMap.get(DevicePropertyTypeEnum.DB_FXYGZ.getType() + "_" + dbcldDevice.getId()).toString());
                    electricMeterValueVO.setZxwgz(dataValueMap.get(DevicePropertyTypeEnum.DB_ZXWGZ.getType() + "_" + dbcldDevice.getId()).toString());
                    electricMeterValueVO.setFxwgz(dataValueMap.get(DevicePropertyTypeEnum.DB_FXWGZ.getType() + "_" + dbcldDevice.getId()).toString());
                    electricMeterValueList.add(electricMeterValueVO);
                } catch (Exception ex) {
                    log.error("查询某个电站下的电表实时采集值，异常", ex);
                    throw new ServiceException("查询某个电站下的电表实时采集值，操作数据源【" + dsTdengine + "】失败");
                } finally {
                    DynamicDataSourceContextHolder.clear();
                }
            }
        });
        return electricMeterValueList;
    }

    @Override
    public Map<String, Object> dbPowerStatistics(Long projectId, Long deviceId, String propertyNo, String queryType, String datetime) {
        Map<String, Object> resultMap = Maps.newHashMap();
        String startTime, endTime;
        if (StatisticsType.STATISTICS_TYPE_YEAR.equals(queryType)) {
            DateTime startDay = DateTime.of(datetime + "-01-01", "yyyy-MM-dd");
            DateTime endDay = DateTime.of(datetime + "-12-31", "yyyy-MM-dd");
            startTime = DateUtil.format(DateUtil.beginOfDay(startDay), "yyyy-MM-dd HH:mm:ss");
            endTime = DateUtil.format(DateUtil.endOfDay(endDay), "yyyy-MM-dd HH:mm:ss");
        } else if (StatisticsType.STATISTICS_TYPE_MONTH.equals(queryType)) {
            DateTime dayDateTime = DateTime.of(datetime + "-01", "yyyy-MM-dd");
            DateTime startDay = DateUtil.beginOfMonth(dayDateTime);
            DateTime endOfMonth = DateUtil.endOfMonth(dayDateTime);
            startTime = DateUtil.format(startDay, "yyyy-MM-dd HH:mm:ss");
            endTime = DateUtil.format(endOfMonth, "yyyy-MM-dd HH:mm:ss");
        } else if (StatisticsType.STATISTICS_TYPE_DAY.equals(queryType)) {
            DateTime dayDateTime = DateTime.of(datetime, "yyyy-MM-dd");
            DateTime startDay = DateUtil.beginOfDay(dayDateTime);
            DateTime endDay = DateUtil.endOfDay(dayDateTime);
            startTime = DateUtil.format(startDay, "yyyy-MM-dd HH:mm:ss");
            endTime = DateUtil.format(endDay, "yyyy-MM-dd HH:mm:ss");
        } else {
            throw new ServiceException("暂不支持" + queryType + "查询类型");
        }
        String tableName = "property_" + projectId + "_" + deviceId + "_0";
        String sql = "SELECT first(`" + propertyNo + "`) AS startValue, last_row(`" + propertyNo + "`) AS endValue, last_row(`" + propertyNo + "`) - first(`" + propertyNo + "`) AS diffValue "
                + " FROM " + tableName
                + " WHERE `time` >= '" + startTime + "' and `time` <= '" + endTime + "' ";
        String dsTdengine = SystemConstant.DS_TDENGINE;
        try {
            DynamicDataSourceContextHolder.push(dsTdengine);
            String currentDs = DynamicDataSourceContextHolder.peek();
            resultMap = iotDatasourceMapper.parseMap4TDengine(sql);
        } catch (Exception ex) {
            log.error("按指定类型(按日、按月、按年)及时间查询电表起始、结束功率值，异常", ex);
            throw new ServiceException("按指定类型(按日、按月、按年)及时间查询电表起始、结束功率值，操作数据源【" + dsTdengine + "】失败");
        } finally {
            DynamicDataSourceContextHolder.clear();
        }
        return resultMap;
    }

    @Override
    public Map<String, Object> dbPropertyValueMap(Long projectId, Long powerStationId) {
        List<ElectricMeterValueVO> dbPropertyValueList = this.dbPropertyValueList(projectId, powerStationId);
        List<Map<String, Object>> dimensions = new ArrayList() {{
            this.add(new HashMap<>() {{
                this.put("title", "测量点");
                this.put("key", "测量点");
            }});
            this.add(new HashMap<>() {{
                this.put("title", "正向有功总");
                this.put("key", "正向有功总");
            }});
            this.add(new HashMap<>() {{
                this.put("title", "反向有功总");
                this.put("key", "反向有功总");
            }});
            this.add(new HashMap<>() {{
                this.put("title", "正向无功总");
                this.put("key", "正向无功总");
            }});
            this.add(new HashMap<>() {{
                this.put("title", "反向无功总");
                this.put("key", "反向无功总");
            }});
        }};
        List<Map<String, Object>> source = Lists.newArrayList();
        dbPropertyValueList.forEach(electricMeterValueVO ->
                source.add(new HashMap<>() {{
                    this.put("测量点", electricMeterValueVO.getPointName());
                    this.put("正向有功总", electricMeterValueVO.getZxygz());
                    this.put("反向有功总", electricMeterValueVO.getFxygz());
                    this.put("正向无功总", electricMeterValueVO.getZxwgz());
                    this.put("反向无功总", electricMeterValueVO.getFxwgz());
                }}));
        Map<String, Object> resultMap = Maps.newHashMap();
        resultMap.put("dimensions", dimensions);
        resultMap.put("source", source);
        return resultMap;
    }

    private List<Tree<String>> buildDeviceRelationTree(List<DeviceRelationWithPropertyValueVO> deviceRelationList, String rootId) {
        List<TreeNode<String>> treeNodeList = deviceRelationList.stream().map(deviceRelation -> {
            Map<String, Object> map = Maps.newHashMap();
            map.put("projectId", deviceRelation.getProjectId());
            map.put("powerStationId", deviceRelation.getPowerStationId());
            map.put("isRealDevice", deviceRelation.getIsRealDevice());
            map.put("deviceId", deviceRelation.getDeviceId());
            map.put("deviceType", deviceRelation.getDeviceType());
            map.put("propertyId", deviceRelation.getPropertyId());
            map.put("propertyNo", deviceRelation.getPropertyNo());
            map.put("propertyValue", deviceRelation.getPropertyValue());
            map.put("propertyType", deviceRelation.getPropertyType());
            map.put("propertyUnit", deviceRelation.getPropertyUnit());
            map.put("propertyIcon", deviceRelation.getPropertyIcon());
            map.put("sortNo", deviceRelation.getSortNo());
            return new TreeNode<String>()
                    .setId(String.valueOf(deviceRelation.getId()))
                    .setName(deviceRelation.getName())
                    .setParentId(String.valueOf(deviceRelation.getParentId()))
                    // .setWeight(deviceRelation.getSortNo())
                    .setExtra(map);
        }).collect(Collectors.toList());
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setIdKey("id");
        treeNodeConfig.setParentIdKey("parentId");
        treeNodeConfig.setNameKey("name");
        treeNodeConfig.setWeightKey("sortNo");
        return TreeUtil.build(treeNodeList, rootId, treeNodeConfig, (treeNode, tree) -> {
            tree.setId(treeNode.getId());
            tree.setParentId(treeNode.getParentId());
            // tree.setWeight(treeNode.getWeight());
            tree.setName(treeNode.getName());
            tree.putExtra("projectId", treeNode.getExtra().getOrDefault("projectId", ""));
            tree.putExtra("powerStationId", treeNode.getExtra().getOrDefault("powerStationId", ""));
            tree.putExtra("isRealDevice", treeNode.getExtra().getOrDefault("isRealDevice", ""));
            tree.putExtra("deviceId", treeNode.getExtra().getOrDefault("deviceId", ""));
            tree.putExtra("deviceType", treeNode.getExtra().getOrDefault("deviceType", ""));
            tree.putExtra("propertyId", treeNode.getExtra().getOrDefault("propertyId", ""));
            tree.putExtra("propertyNo", treeNode.getExtra().getOrDefault("propertyNo", ""));
            tree.putExtra("propertyValue", treeNode.getExtra().getOrDefault("propertyValue", ""));
            tree.putExtra("propertyType", treeNode.getExtra().getOrDefault("propertyType", ""));
            tree.putExtra("propertyUnit", treeNode.getExtra().getOrDefault("propertyUnit", ""));
            tree.putExtra("propertyIcon", treeNode.getExtra().getOrDefault("propertyIcon", ""));
            tree.putExtra("sortNo", treeNode.getExtra().getOrDefault("sortNo", ""));
        });
    }

    @Data
    private static class MpptPvDTO implements Serializable {
        private static final long serialVersionUID = 1L;

        private Long parentId;
        private String dy;
        private String dl;
    }
}
